using System;
using System.Collections.Generic;
using System.Linq;
using MEA.AE_Data.Config;

namespace MEA.AE_BusinessLogic
{
	public class RecManLeadInOut
	{
		public struct SLeadInOutInfo
		{
			public enum ELiLoStatus
			{
				eData,
				eFirstData,
				eLastData,
				eLastDataOk,
				eDataNoLiLo,
				eNoUsableLiLo
			}

			public int leadInIx;

			public int leadOutIx;

			public DateTime LeadInTime;

			public DateTime LeadOutTime;

			public List<ushort> channelnrs;

			public int dataCnt;

			public ELiLoStatus vLiLoStatus;

			public List<float[]> DataOfSequenceList;

			public List<DateTime> DataTimeStampsList;

			public bool TimeStampLiOutOk;

			public bool ConfigurationOk;

			public bool LeadInTimeOk;

			public bool LeadOutTimeOk;

			public bool LeadInChkSumOk;

			public bool LeadOutChkSumOk;

			public string sLiLoNote;

			public void writeNote(ConfigData.e_ECUID ab)
			{
				switch (vLiLoStatus)
				{
				case ELiLoStatus.eNoUsableLiLo:
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Position Lead-In {1} - Lead-Out {2}", ab, leadInIx, leadOutIx);
					}
					sLiLoNote += string.Format("\\line Sequence not usable !");
					return;
				case ELiLoStatus.eDataNoLiLo:
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Sequence without Lead-In and Lead-Out information.");
					return;
				}
				if (!LeadInChkSumOk)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-In Checksumme not OK");
				}
				if (!LeadInTimeOk)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-In Time stamp not OK");
				}
				if (!ConfigurationOk)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-In Configuration not OK", LeadInTime, LeadOutTime);
				}
				if (!LeadOutChkSumOk)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-Out Checksumme not OK", LeadInTime, LeadOutTime);
				}
				if (!LeadOutTimeOk)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-Out Time stamp not OK", LeadInTime, LeadOutTime);
				}
				if (dataCnt == 0)
				{
					if (sLiLoNote == null)
					{
						sLiLoNote = string.Format("\\line ECU-{0}: Lead-In {1} - Lead-Out {2}", ab, LeadInTime, LeadOutTime);
					}
					sLiLoNote += string.Format("\\line Lead-In Lead-Out Sequence without data", LeadInTime, LeadOutTime);
				}
				if (!LeadInChkSumOk)
				{
					sLiLoNote += ". \\b Sequence not usable\\b0";
				}
			}

			public bool findLeadInOfLastSession(ref List<byte> data, int chanCntr)
			{
				bool flag = false;
				dataCnt = 0;
				int num = chanCntr;
				num = (((num & 1) != 0) ? ((num + 1) * 2) : (num * 2));
				int num2 = leadOutIx - num;
				while (num2 >= num)
				{
					int num3 = num2 + num;
					if (ifSectorChangeDown(num2, num3))
					{
						num3 = num3 / 65528 * 65528;
						while (num3 >= num2 && data[--num3] == byte.MaxValue)
						{
						}
						num2 = num3 - num + 1;
					}
					else
					{
						num2 -= num;
						dataCnt++;
					}
				}
				flag = true;
				leadInIx = 0;
				vLiLoStatus = ELiLoStatus.eLastData;
				return flag;
			}

			private bool ifSectorChangeDown(int lastVal, int firstVal)
			{
				bool result = false;
				if (lastVal / 65528 != firstVal / 65528)
				{
					result = true;
				}
				return result;
			}

			public bool findLeadOutFirstSession(ref List<byte> data, int chanCntr)
			{
				bool flag = false;
				dataCnt = 0;
				int num = chanCntr;
				num = (((num & 1) != 0) ? ((num + 1) * 2) : (num * 2));
				for (int i = leadInIx; i < data.Count; i += num)
				{
					if (flag)
					{
						break;
					}
					if (i + num < data.Count - 1)
					{
						if (ifSectorChangeUp(ref i, i + num))
						{
							i -= num;
							continue;
						}
						dataCnt++;
						for (int j = 0; j < num; j++)
						{
							if (j == num - 1)
							{
								flag = true;
								dataCnt++;
								leadOutIx = i;
								vLiLoStatus = ELiLoStatus.eFirstData;
							}
							else if (data[i + j] != byte.MaxValue)
							{
								break;
							}
						}
						continue;
					}
					flag = true;
					leadOutIx = i - num + 1;
					vLiLoStatus = ELiLoStatus.eFirstData;
					break;
				}
				return flag;
			}

			public bool findLeadOutSessionNoLeadInOut(ref List<byte> data, int chanCntr)
			{
				bool result = false;
				dataCnt = 0;
				leadInIx = 0;
				findLeadOutFirstSession(ref data, chanCntr);
				vLiLoStatus = ELiLoStatus.eDataNoLiLo;
				return result;
			}

			private bool ifSectorChangeUp(ref int posStart, int posEnd)
			{
				bool result = false;
				int num = posEnd / 65528;
				if (posStart / 65528 != num)
				{
					posStart = num * 65528;
					result = true;
				}
				return result;
			}

			public bool testChecksumLeadIn(ref List<byte> data)
			{
				bool result = false;
				byte b = 0;
				for (int i = leadInIx - 32; i < leadInIx; i++)
				{
					b += data[i];
				}
				if (b == byte.MaxValue)
				{
					result = true;
				}
				return result;
			}

			public bool testChecksumLeadOut(ref List<byte> data)
			{
				bool result = false;
				byte b = 0;
				for (int i = leadOutIx; i < leadOutIx + 32; i++)
				{
					b += data[i];
				}
				if (b == byte.MaxValue)
				{
					result = true;
				}
				return result;
			}

			public bool analizeLiLoSeq(ref List<byte> data, ref DateTime actTime)
			{
				if (leadOutIx >= leadInIx)
				{
					switch (vLiLoStatus)
					{
					case ELiLoStatus.eFirstData:
						LeadInChkSumOk = testChecksumLeadIn(ref data);
						LeadInTimeOk = mkRecManTime(ref data, ref LeadInTime, leadInIx - 32);
						ConfigurationOk = mkRecManChanConf(ref data, leadInIx - 25 - 1);
						LeadOutChkSumOk = true;
						mkRecManDataList(ref data);
						if (LeadInTimeOk)
						{
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadOutTime = LeadInTime + timeSpan;
							LeadOutTimeOk = true;
						}
						else
						{
							LeadOutTime = actTime;
							LeadOutTimeOk = false;
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadInTime = LeadOutTime - timeSpan;
							LeadInTimeOk = false;
						}
						break;
					case ELiLoStatus.eLastData:
						LeadOutChkSumOk = testChecksumLeadOut(ref data);
						LeadOutTimeOk = mkRecManTime(ref data, ref LeadOutTime, leadOutIx + 25);
						ConfigurationOk = mkRecManChanConf(ref data, 0);
						LeadInTimeOk = true;
						LeadInChkSumOk = true;
						mkRecManDataList(ref data);
						if (LeadOutTimeOk)
						{
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadInTime = LeadOutTime - timeSpan;
							LeadOutTimeOk = true;
						}
						else
						{
							LeadOutTime = actTime;
							LeadOutTimeOk = false;
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadInTime = LeadOutTime - timeSpan;
							LeadInTimeOk = false;
						}
						break;
					case ELiLoStatus.eDataNoLiLo:
					{
						LeadOutTime = actTime;
						TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
						LeadInTime = LeadOutTime - timeSpan;
						ConfigurationOk = mkRecManChanConf(ref data, 0);
						LeadInTimeOk = true;
						LeadOutTimeOk = true;
						mkRecManDataList(ref data);
						break;
					}
					default:
						LeadInChkSumOk = testChecksumLeadIn(ref data);
						LeadOutChkSumOk = testChecksumLeadOut(ref data);
						LeadInTimeOk = mkRecManTime(ref data, ref LeadInTime, leadInIx - 32);
						LeadOutTimeOk = mkRecManTime(ref data, ref LeadOutTime, leadOutIx + 25);
						ConfigurationOk = mkRecManChanConf(ref data, leadInIx - 25 - 1);
						mkRecManDataList(ref data);
						if (!LeadInTimeOk && !LeadOutTimeOk)
						{
							LeadOutTime = actTime;
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadInTime = LeadOutTime - timeSpan;
						}
						else if (!LeadInTimeOk)
						{
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadInTime = LeadOutTime - timeSpan;
						}
						else if (!LeadOutTimeOk)
						{
							TimeSpan timeSpan = new TimeSpan(0, 0, dataCnt);
							LeadOutTime = LeadInTime + timeSpan;
						}
						break;
					}
					mkRecManTimeList();
				}
				else
				{
					vLiLoStatus = ELiLoStatus.eNoUsableLiLo;
				}
				return true;
			}

			private void mkRecManTimeList()
			{
				if (DataTimeStampsList == null)
				{
					DataTimeStampsList = new List<DateTime>(DataOfSequenceList.Count);
				}
				TimeSpan value = new TimeSpan(0, 0, 1);
				DateTime dateTime = LeadInTime;
				for (int i = 0; i < DataOfSequenceList.Count; i++)
				{
					DataTimeStampsList.Add(dateTime);
					dateTime = dateTime.Add(value);
				}
				value = dateTime.Subtract(LeadOutTime);
				if (value.TotalSeconds > 4.0 || value.TotalSeconds < -4.0)
				{
					TimeStampLiOutOk = false;
					LeadOutTime = dateTime;
				}
				else
				{
					TimeStampLiOutOk = true;
				}
			}

			private bool mkRecManDataList(ref List<byte> data)
			{
				bool result = false;
				if (vLiLoStatus != ELiLoStatus.eNoUsableLiLo)
				{
					ushort num = 0;
					int posStart = leadInIx;
					int num2 = channelnrs.Count * 2;
					DataOfSequenceList = new List<float[]>((leadOutIx - leadInIx) / num2);
					int num3 = posStart + num2;
					while (num3 < leadOutIx)
					{
						if (!ifSectorChangeUp(ref posStart, num3))
						{
							float[] array = new float[channelnrs.Count];
							for (int i = posStart; i < num3; i += 2)
							{
								int num4 = i - posStart >> 1;
								num = data[i];
								num <<= 8;
								num += data[i + 1];
								if (i == 13)
								{
									array[num4] = (int)num;
								}
								else
								{
									array[num4] = (short)num;
								}
							}
							DataOfSequenceList.Add(array);
							posStart += num2;
							num3 = posStart + num2;
						}
						else
						{
							num3 = posStart + num2;
						}
					}
					if (DataOfSequenceList != null)
					{
						dataCnt = DataOfSequenceList.Count;
					}
				}
				return result;
			}

			private bool mkRecManTime(ref List<byte> data, ref DateTime tm, int tmIx)
			{
				bool result = false;
				byte b = data[tmIx++];
				int num = BaseService.TransformBCDToInt(b);
				b = data[tmIx++];
				int num2 = BaseService.TransformBCDToInt(b);
				b = data[tmIx++];
				int num3 = BaseService.TransformBCDToInt(b);
				b = data[tmIx++];
				int num4 = BaseService.TransformBCDToInt(b);
				b = data[tmIx++];
				int num5 = BaseService.TransformBCDToInt(b);
				b = data[tmIx++];
				int num6 = BaseService.TransformBCDToInt(b);
				if (num >= 0 && num < 120 && num2 > 0 && num2 < 13 && num3 > 0 && num3 < 32 && num4 >= 0 && num4 < 24 && num5 >= 0 && num5 < 60 && num6 >= 0 && num6 < 60)
				{
					tm = new DateTime(2000 + num, num2, num3, num4, num5, num6);
					result = true;
				}
				else
				{
					tm = new DateTime(2049, 1, 1, 0, 0, 0);
				}
				return result;
			}

			private bool mkRecManChanConf(ref List<byte> data, int tmIx)
			{
				bool result = true;
				channelnrs = new List<ushort>(16);
				List<byte> list = new List<byte>(48);
				if (vLiLoStatus == ELiLoStatus.eLastData || vLiLoStatus == ELiLoStatus.eDataNoLiLo)
				{
					for (int i = 0; i < cLeadInConfigBytes.Count(); i++)
					{
						list.Add((byte)(cLeadInConfigBytes[i] >> 4));
						list.Add((byte)(cLeadInConfigBytes[i] & 0xF));
					}
				}
				else
				{
					for (int j = tmIx; j < tmIx + 24; j++)
					{
						byte b = data[j];
						if (vLiLoStatus == ELiLoStatus.eLastData)
						{
							b = cLeadInConfigBytes[j - tmIx];
						}
						else if (b != cLeadInConfigBytes[j - tmIx])
						{
							b = cLeadInConfigBytes[j - tmIx];
							result = false;
						}
						list.Add((byte)(b >> 4));
						list.Add((byte)(b & 0xF));
					}
				}
				for (int k = 0; k < list.Count; k += 3)
				{
					ushort num = (ushort)(list[k] << 8);
					num |= (ushort)((list[k + 1] & 0xF) << 4);
					num |= (ushort)(list[k + 2] & 0xF);
					channelnrs.Add(num);
				}
				return result;
			}
		}

		private const int cLeadInSize = 32;

		private const int cLeadOutSize = 32;

		private const int cConfigSize = 25;

		private const int cTimeStampSize = 6;

		private const int cCheckSumSize = 1;

		private const int cChannelsCnt = 16;

		private DateTime myTime;

		private ConfigData.e_ECUID ab;

		private static byte[] cLeadInConfigBytes = new byte[24]
		{
			50, 3, 33, 50, 35, 35, 50, 67, 37, 50,
			99, 39, 50, 131, 41, 50, 163, 43, 50, 195,
			45, 50, 227, 47
		};

		public List<SLeadInOutInfo> listLeadInOutInfo;

		public RecManLeadInOut(ref List<byte> dataPayLoad, ref string fileTime, ConfigData.e_ECUID ab)
		{
			this.ab = ab;
			listLeadInOutInfo = new List<SLeadInOutInfo>();
			SLeadInOutInfo sLeadInOutInfo = default(SLeadInOutInfo);
			int num = dataPayLoad.Count - 1;
			if (num <= 32)
			{
				return;
			}
			findLoPos(ref dataPayLoad);
			string[] array = fileTime.Split(' ');
			string[] array2 = array[0].Split('.');
			string[] array3 = array[1].Split(':');
			myTime = new DateTime(int.Parse(array2[2]), int.Parse(array2[1]), int.Parse(array2[0]), int.Parse(array3[0]), int.Parse(array3[1]), int.Parse(array3[2]));
			if (listLeadInOutInfo.Count == 1)
			{
				sLeadInOutInfo = listLeadInOutInfo[0];
				sLeadInOutInfo.vLiLoStatus = SLeadInOutInfo.ELiLoStatus.eDataNoLiLo;
				sLeadInOutInfo.findLeadOutSessionNoLeadInOut(ref dataPayLoad, 16);
				sLeadInOutInfo.analizeLiLoSeq(ref dataPayLoad, ref myTime);
				sLeadInOutInfo.writeNote(ab);
				listLeadInOutInfo[0] = sLeadInOutInfo;
				return;
			}
			sLeadInOutInfo = listLeadInOutInfo[listLeadInOutInfo.Count - 1];
			sLeadInOutInfo.findLeadInOfLastSession(ref dataPayLoad, 16);
			listLeadInOutInfo[listLeadInOutInfo.Count - 1] = sLeadInOutInfo;
			sLeadInOutInfo = listLeadInOutInfo[0];
			sLeadInOutInfo.findLeadOutFirstSession(ref dataPayLoad, 16);
			listLeadInOutInfo[0] = sLeadInOutInfo;
			for (int i = 0; i < listLeadInOutInfo.Count; i++)
			{
				sLeadInOutInfo = listLeadInOutInfo[i];
				sLeadInOutInfo.analizeLiLoSeq(ref dataPayLoad, ref myTime);
				sLeadInOutInfo.writeNote(ab);
				if (!sLeadInOutInfo.LeadInChkSumOk)
				{
					sLeadInOutInfo.vLiLoStatus = SLeadInOutInfo.ELiLoStatus.eNoUsableLiLo;
				}
				listLeadInOutInfo[i] = sLeadInOutInfo;
			}
		}

		private void findLoPos(ref List<byte> dataPayLoad)
		{
			SLeadInOutInfo item = default(SLeadInOutInfo);
			int num = dataPayLoad.Count - 1;
			int num2 = 0;
			while (num >= 32)
			{
				if (dataPayLoad[num--] == 0)
				{
					num2++;
					if (num2 == 25)
					{
						num2 = 0;
						item.leadInIx = num + 1 + 32 + 32;
						item.testChecksumLeadIn(ref dataPayLoad);
						listLeadInOutInfo.Add(item);
						item = default(SLeadInOutInfo);
						item.leadOutIx = num + 1;
						item.testChecksumLeadOut(ref dataPayLoad);
					}
				}
				else
				{
					num2 = 0;
				}
			}
			listLeadInOutInfo.Add(item);
		}
	}
}
